/* Includes ------------------------------------------------------------------*/
#include "SystemTick.h"
#include "Led.h"
#include "RF.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define NUMBER_RF_BIT           12          //12 bit 3 trang thai
#define RF_CODE_SIZE_IN_EEPROM  3
#define RF_CODE_SIZE            3
#define TIMEOUT_RF              300         //khoang 300ms
#define TIMEOUT_LEARN_RF        5000        //khoang 5s
#define TIM2_PERIOD             0xFFFF      // reset counter

#define RF_START_CODE           0x03
#define RF_PAUSE_CODE           0x0C
#define WAITING_FOR_RETURN_NORMAL_TIMER       1000        //khoang 1s
#define WAITING_FOR_RETURN_LEARN_TIMER        2000        //khoang 2s

#define TOGGLE_LED_LEARN_START_PERIOD       100         //khoang 100ms
#define TOGGLE_LED_LEARN_PAUSE_PERIOD       400         //khoang 400ms

#define BLOCK_OPERATION    0    /* block 0 in data eeprom memory: address is 0x4000 */

#define ADDRESS_START_BUTTON1     (FLASH_DATA_START_PHYSICAL_ADDRESS + ((U16)BLOCK_OPERATION * (U16)FLASH_BLOCK_SIZE))
#define ADDRESS_START_BUTTON2     (ADDRESS_START_BUTTON1 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_START_BUTTON3     (ADDRESS_START_BUTTON2 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_START_BUTTON4     (ADDRESS_START_BUTTON3 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_START_BUTTON5     (ADDRESS_START_BUTTON4 + RF_CODE_SIZE_IN_EEPROM)

#define ADDRESS_PAUSE_BUTTON1     (ADDRESS_START_BUTTON5 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_PAUSE_BUTTON2     (ADDRESS_PAUSE_BUTTON1 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_PAUSE_BUTTON3     (ADDRESS_PAUSE_BUTTON2 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_PAUSE_BUTTON4     (ADDRESS_PAUSE_BUTTON3 + RF_CODE_SIZE_IN_EEPROM)
#define ADDRESS_PAUSE_BUTTON5     (ADDRESS_PAUSE_BUTTON4 + RF_CODE_SIZE_IN_EEPROM)

/* Private macro -------------------------------------------------------------*/
#define start_timer()      {TIM2_SetCounter(0); TIM2_Cmd(ENABLE);}
#define reset_timer()      TIM2_SetCounter(0)
#define stop_timer()       TIM2_Cmd(DISABLE)
#define get_timer()        TIM2_GetCounter()

/* Private variables ---------------------------------------------------------*/
__IO BitStatus  v_RfIn;
__IO U16        v_TimeLow = 0;
__IO U16        v_TimeHigh = 0;
__IO bool       v_ReceiveFlag = false;
U8  s_BitCnt;
U8  s_pRFBuff[RF_CODE_SIZE];
U8  s_pRFIncome[RF_CODE_SIZE];
U16 s_RFSysnBitTimeout = 0xFFFF;

U8  s_pCodeStartButton[5][RF_CODE_SIZE_IN_EEPROM];
U8  s_pCodePauseButton[5][RF_CODE_SIZE_IN_EEPROM];
U8  s_ButtonIndex;

eRfMode s_Mode;
U16     s_TimeoutLearnCnt = 0;
U16     s_ToggleLedCnt = 0;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/

/**
  * @brief  External Interrupt PORTC Interrupt routine
  * @param  None
  * @retval None
  */
INTERRUPT_HANDLER(EXTI_PORTC_IRQHandler, 5)
{
    v_RfIn = GPIO_ReadInputPin(RF_PORT, RF_PINS);
    stop_timer();
    if(RESET == v_RfIn)
    {
        v_TimeHigh = get_timer();
    }
    else
    {
        v_TimeLow = get_timer();
        v_ReceiveFlag = true;
    }
    start_timer();
}


  /**
  * @brief  Timer2 Update/Overflow/Break Interrupt routine
  * @param  None
  * @retval None
  */
 INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
{
    /* Cleat Interrupt Pending bit */
    TIM2_ClearITPendingBit(TIM2_IT_UPDATE);
    stop_timer();
}



bool RF_receive( void )
{
    U16 timeHigh;
    U16 timeLow;
    U8 byteIndex;
    U8 temp;

    if(false == v_ReceiveFlag) return (false);
    v_ReceiveFlag = false;

    timeHigh = v_TimeHigh;
    timeLow = v_TimeLow;

    if ((timeHigh > (timeLow<<1)) && (timeHigh < (timeLow<<3)))
    {
        byteIndex = (s_BitCnt>>3) & 0x03;
        temp = s_pRFBuff[byteIndex]<<1;
        s_pRFBuff[byteIndex] = temp | 1;
    }
    else if ((timeLow > (timeHigh<<1)) && (timeLow < (timeHigh<<3)))
    {
        byteIndex = (s_BitCnt>>3) & 0x03;
        temp = s_pRFBuff[byteIndex]<<1;
        s_pRFBuff[byteIndex] = temp;
    }
    else
    {
        s_BitCnt = 0;
        return (false);
    }

    s_BitCnt++;
    if ((NUMBER_RF_BIT*2) <= s_BitCnt)
    {
        stop_timer();
        s_pRFIncome[0] = s_pRFBuff[0];
        s_pRFIncome[1] = s_pRFBuff[1];
        s_pRFIncome[2] = s_pRFBuff[2];
        s_BitCnt = 0;
        if(s_RFSysnBitTimeout > TIMEOUT_RF)
        {
            s_RFSysnBitTimeout = 0;
            return (true);
        }
        s_RFSysnBitTimeout = 0;
    }

    return (false);
}


void Rf_TimerInterrupt(void)
{
    if( 0xFFF0 > s_RFSysnBitTimeout ) ++s_RFSysnBitTimeout;
    if( 0xFFFF > s_TimeoutLearnCnt ) ++s_TimeoutLearnCnt;
    ++s_ToggleLedCnt;
}


void Rf_Init(void)
{
    U32 addr;
    // Initialize I/Os in Input Mode and external interrupt
    GPIO_Init(RF_PORT, RF_PINS, GPIO_MODE_IN_PU_IT);
    EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOC, EXTI_SENSITIVITY_RISE_FALL);

    /* Define flash programming Time*/
    FLASH_SetProgrammingTime(FLASH_PROGRAMTIME_STANDARD);
    FLASH_Unlock(FLASH_MEMTYPE_PROG);
    /* Wait until Flash Program area unlocked flag is set*/
    while (FLASH_GetFlagStatus(FLASH_FLAG_PUL) == RESET);
    /* Unlock flash data eeprom memory */
    FLASH_Unlock(FLASH_MEMTYPE_DATA);
    /* Wait until Data EEPROM area unlocked flag is set*/
    while (FLASH_GetFlagStatus(FLASH_FLAG_DUL) == RESET);

    addr = ADDRESS_START_BUTTON1;
    s_pCodeStartButton[0][0] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[0][1] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[0][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_START_BUTTON2;
    s_pCodeStartButton[1][0] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[1][1] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[1][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_START_BUTTON3;
    s_pCodeStartButton[2][0] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[2][1] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[2][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_START_BUTTON4;
    s_pCodeStartButton[3][0] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[3][1] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[3][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_START_BUTTON5;
    s_pCodeStartButton[4][0] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[4][1] = FLASH_ReadByte(addr++);
    s_pCodeStartButton[4][2] = FLASH_ReadByte(addr);

    addr = ADDRESS_PAUSE_BUTTON1;
    s_pCodePauseButton[0][0] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[0][1] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[0][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_PAUSE_BUTTON2;
    s_pCodePauseButton[1][0] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[1][1] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[1][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_PAUSE_BUTTON3;
    s_pCodePauseButton[2][0] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[2][1] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[2][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_PAUSE_BUTTON4;
    s_pCodePauseButton[3][0] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[3][1] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[3][2] = FLASH_ReadByte(addr);
    addr = ADDRESS_PAUSE_BUTTON5;
    s_pCodePauseButton[4][0] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[4][1] = FLASH_ReadByte(addr++);
    s_pCodePauseButton[4][2] = FLASH_ReadByte(addr);

    /* Time base configuration */
    TIM2_TimeBaseInit(TIM2_PRESCALER_16, TIM2_PERIOD);
    /* Clear TIM2 update flag */
    TIM2_ClearFlag(TIM2_FLAG_UPDATE);
    /* Enable update interrupt */
    TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);

    SysTick_Registration(&Rf_TimerInterrupt);

    v_RfIn = RESET;
    s_Mode = NORMAL;
}


bool RF_IsStartExist(void)
{
    U8 i;
    for (i=0; i<5; i++)
    {
        if( s_pRFIncome[0] == s_pCodeStartButton[i][0] && s_pRFIncome[1] == s_pCodeStartButton[i][1] && s_pRFIncome[2] == s_pCodeStartButton[i][2] )
        {
            return (true);
        }
    }
    return (false);
}

bool RF_IsPauseExist(void)
{
    U8 i;
    for (i=0; i<5; i++)
    {
        if( s_pRFIncome[0] == s_pCodePauseButton[i][0] && s_pRFIncome[1] == s_pCodePauseButton[i][1] && s_pRFIncome[2] == s_pCodePauseButton[i][2] )
        {
            return (true);
        }
    }
    return (false);
}

eRfMode Rf_GetMode( void )
{
    return (s_Mode);
}


void Rf_SetMode( eRfMode iMode )
{
    s_Mode = iMode;
    s_TimeoutLearnCnt = 0;
}


void Rf_RunOne(void)
{
    U8  i;
    U32 addr;
    
    switch( s_Mode )
    {
    default:
    case NORMAL:
        {
            if( true == RF_receive() )
            {
                if( true == RF_IsStartExist() )
                {
                    Led_SetOutput( START_BUTTON, false );
                    Beep_1();
                    Rf_SetMode( WAITING_FOR_RETURN_NORMAL );
                }
                else if( true == RF_IsPauseExist() )
                {
                    Led_SetOutput( PAUSE_BUTTON, false );
                    Beep_2();
                    Rf_SetMode( WAITING_FOR_RETURN_NORMAL );
                }
            }
        } break;
    case WAITING_FOR_RETURN_NORMAL:
        {
            if( WAITING_FOR_RETURN_NORMAL_TIMER < s_TimeoutLearnCnt )
            {
                Led_SetOutput( START_BUTTON, true );
                Led_SetOutput( PAUSE_BUTTON, true );
                Rf_SetMode( NORMAL );
            }
        } break;

    case ENTER_LEARN:
        {
            Beep_Long();
            Led_SetOutput( STATUS_LED, false );
            for (i=0; i<5; i++)
            {
                s_pCodeStartButton[i][0] = 0;
                s_pCodeStartButton[i][1] = 0;
                s_pCodeStartButton[i][2] = 0;
                s_pCodePauseButton[i][0] = 0;
                s_pCodePauseButton[i][1] = 0;
                s_pCodePauseButton[i][2] = 0;
            }
            s_ButtonIndex = 0;
            s_ToggleLedCnt = 0;
            Rf_SetMode( LEARN_START_PROCESS );
        } break;

    case LEARN_START_PROCESS:
        {
            if( true == RF_receive() )
            {
                if( true == RF_IsStartExist() || true == RF_IsPauseExist() )
                {
                    // da co ma duoc hoc roi
                    Beep_3();
                    Led_SetOutput( STATUS_LED, false );
                    Rf_SetMode( WAITING_FOR_RETURN_LEARN_START );
                }
                else
                {
                    // la ma moi, chua duoc hoc lan nao
                    s_pCodeStartButton[s_ButtonIndex][0] = s_pRFIncome[0];
                    s_pCodeStartButton[s_ButtonIndex][1] = s_pRFIncome[1];
                    s_pCodeStartButton[s_ButtonIndex][2] = s_pRFIncome[2];
                    Beep_1();
                    Led_SetOutput( STATUS_LED, true );
                    Rf_SetMode( WAITING_FOR_RETURN_LEARN_PAUSE );
                }
            }
            
            if( TIMEOUT_LEARN_RF <= s_TimeoutLearnCnt || 5 <= s_ButtonIndex )
            {
                Rf_SetMode( QUIT_LEARN );
            }
            
            if( TOGGLE_LED_LEARN_START_PERIOD < s_ToggleLedCnt )
            {
                s_ToggleLedCnt = 0;
                Led_InvOutput( STATUS_LED );
            }
        } break;

    case WAITING_FOR_RETURN_LEARN_START:
        {
            if( WAITING_FOR_RETURN_LEARN_TIMER < s_TimeoutLearnCnt )
            {
                Led_SetOutput( STATUS_LED, false );
                s_ToggleLedCnt = 0;
                Rf_SetMode( LEARN_START_PROCESS );
            }
        } break;

    case LEARN_PAUSE_PROCESS:
        {
            if( true == RF_receive() )
            {
                if( true == RF_IsStartExist() || true == RF_IsPauseExist() )
                {
                    // da co ma duoc hoc roi
                    Beep_3();
                    Led_SetOutput( STATUS_LED, false );
                    Rf_SetMode( WAITING_FOR_RETURN_LEARN_PAUSE );
                }
                else
                {
                    // la ma moi, chua duoc hoc lan nao
                    s_pCodePauseButton[s_ButtonIndex][0] = s_pRFIncome[0];
                    s_pCodePauseButton[s_ButtonIndex][1] = s_pRFIncome[1];
                    s_pCodePauseButton[s_ButtonIndex][2] = s_pRFIncome[2];
                    ++s_ButtonIndex;
                    Beep_2();
                    Led_SetOutput( STATUS_LED, true );
                    Rf_SetMode( WAITING_FOR_RETURN_LEARN_START );
                }
            }
            
            if( TIMEOUT_LEARN_RF <= s_TimeoutLearnCnt || 5 <= s_ButtonIndex )
            {
                Rf_SetMode( QUIT_LEARN );
            }
            
            if( TOGGLE_LED_LEARN_PAUSE_PERIOD < s_ToggleLedCnt )
            {
                s_ToggleLedCnt = 0;
                Led_InvOutput( STATUS_LED );
            }
        } break;

    case WAITING_FOR_RETURN_LEARN_PAUSE:
        {
            if( WAITING_FOR_RETURN_LEARN_TIMER < s_TimeoutLearnCnt )
            {
                Led_SetOutput( STATUS_LED, false );
                s_ToggleLedCnt = 0;
                Rf_SetMode( LEARN_PAUSE_PROCESS );
            }
        } break;

    case QUIT_LEARN:
        {
            addr = ADDRESS_START_BUTTON1;
            FLASH_ProgramByte( addr++, s_pCodeStartButton[0][0] );
            FLASH_ProgramByte( addr++, s_pCodeStartButton[0][1] );
            FLASH_ProgramByte( addr,   s_pCodeStartButton[0][2] );
            addr = ADDRESS_START_BUTTON2;
            FLASH_ProgramByte( addr++, s_pCodeStartButton[1][0] );
            FLASH_ProgramByte( addr++, s_pCodeStartButton[1][1] );
            FLASH_ProgramByte( addr,   s_pCodeStartButton[1][2] );
            addr = ADDRESS_START_BUTTON3;
            FLASH_ProgramByte( addr++, s_pCodeStartButton[2][0] );
            FLASH_ProgramByte( addr++, s_pCodeStartButton[2][1] );
            FLASH_ProgramByte( addr,   s_pCodeStartButton[2][2] );
            addr = ADDRESS_START_BUTTON4;
            FLASH_ProgramByte( addr++, s_pCodeStartButton[3][0] );
            FLASH_ProgramByte( addr++, s_pCodeStartButton[3][1] );
            FLASH_ProgramByte( addr,   s_pCodeStartButton[3][2] );
            addr = ADDRESS_START_BUTTON5;
            FLASH_ProgramByte( addr++, s_pCodeStartButton[4][0] );
            FLASH_ProgramByte( addr++, s_pCodeStartButton[4][1] );
            FLASH_ProgramByte( addr,   s_pCodeStartButton[4][2] );

            addr = ADDRESS_PAUSE_BUTTON1;
            FLASH_ProgramByte( addr++, s_pCodePauseButton[0][0] );
            FLASH_ProgramByte( addr++, s_pCodePauseButton[0][1] );
            FLASH_ProgramByte( addr,   s_pCodePauseButton[0][2] );
            addr = ADDRESS_PAUSE_BUTTON2;
            FLASH_ProgramByte( addr++, s_pCodePauseButton[1][0] );
            FLASH_ProgramByte( addr++, s_pCodePauseButton[1][1] );
            FLASH_ProgramByte( addr,   s_pCodePauseButton[1][2] );
            addr = ADDRESS_PAUSE_BUTTON3;
            FLASH_ProgramByte( addr++, s_pCodePauseButton[2][0] );
            FLASH_ProgramByte( addr++, s_pCodePauseButton[2][1] );
            FLASH_ProgramByte( addr,   s_pCodePauseButton[2][2] );
            addr = ADDRESS_PAUSE_BUTTON4;
            FLASH_ProgramByte( addr++, s_pCodePauseButton[3][0] );
            FLASH_ProgramByte( addr++, s_pCodePauseButton[3][1] );
            FLASH_ProgramByte( addr,   s_pCodePauseButton[3][2] );
            addr = ADDRESS_PAUSE_BUTTON5;
            FLASH_ProgramByte( addr++, s_pCodePauseButton[4][0] );
            FLASH_ProgramByte( addr++, s_pCodePauseButton[4][1] );
            FLASH_ProgramByte( addr,   s_pCodePauseButton[4][2] );

            Led_SetOutput( STATUS_LED, false );
            Led_SetOutput( STATUS_BEEP, false );
            Rf_SetMode( NORMAL );
        } break;
    }
}
